package cidr

import (
	"net"
	"sync"
)

type (
	MaskType string

	NetMask struct {
		*net.IPNet
		Type MaskType
		Tag  string // 标签 自定义业务判断
	}

	Option func(m *Manager)

	Manager struct {
		mu             sync.RWMutex
		isDefaultAllow bool // 默认是否允许(node没匹配)
		nodes          []*NetMask
	}
)

const (
	// Allow 允许
	Allow MaskType = "allow"
	// Deny 拒绝
	Deny MaskType = "deny"
)

var (
	ruleTypes = []MaskType{Allow, Deny}
)

func New(opts ...Option) (*Manager, error) {
	m := &Manager{
		isDefaultAllow: false,
		nodes:          make([]*NetMask, 0),
	}
	for _, opt := range opts {
		opt(m)
	}

	return m, nil
}

func (m *Manager) PushNodes(n *NetMask) {
	m.mu.Lock()
	defer m.mu.Unlock()

	m.nodes = append(m.nodes, n)
}

func (m *Manager) SetNodes(l []*NetMask) {
	m.mu.Lock()
	defer m.mu.Unlock()

	clear(m.nodes)
	m.nodes = l
}

func (m *Manager) CLearNodes() {
	m.mu.Lock()
	defer m.mu.Unlock()

	clear(m.nodes)
}

func (m *Manager) IsAllow(ip net.IP) bool {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for _, n := range m.nodes {
		if n.Contains(ip) {
			switch n.Type {
			case Allow:
				return true
			case Deny:
				return false
			default:
				/* 未知类型忽略 */
				continue
			}
		}
	}

	/* 未匹配返回默认规则 */
	return m.isDefaultAllow
}

func (m *Manager) Find(ip net.IP) *NetMask {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for _, n := range m.nodes {
		if n.Contains(ip) {
			return n
		}
	}
	return nil
}

// WithDefaultAllow 默认允许
func WithDefaultAllow(l bool) Option {
	return func(m *Manager) {
		m.isDefaultAllow = l
	}
}
